#include "RustBuildFileVisitor.h"
#include <iostream>

RustBuildFileVisitor::RustBuildFileVisitor(
    const std::string& outputDir,
    const std::string& idlFileName,
    CLangTypeNameVisitor* typeNameVisitor,
    CLangTypeHeaderVisitor* headerVisitor)
    : FileGenVisitor(outputDir, "build.rs")
    , typeNameVisitor_(typeNameVisitor)
    , headerVisitor_(headerVisitor) 
    , idlFileName_(idlFileName) {
}

RustBuildFileVisitor::~RustBuildFileVisitor() {
}

void RustBuildFileVisitor::visit(SpecificationNode& node) {
    // 获取包名，通常可用文件名或类型名
    std::string packageName = idlFileName_;
    auto pos = packageName.find_last_of('.');
    if (pos != std::string::npos) {
        packageName = packageName.substr(0, pos);
    }
    generateBuildRs(packageName);
    writeToFile();
}

void RustBuildFileVisitor::generateBuildRs(const std::string& packageName) {
    // 生成build.rs内容，模板参考实际build.rs
    content_  = "use std::env;\n";
    content_ += "use std::path::PathBuf;\n";
    content_ += "use bindgen::callbacks::{ParseCallbacks, ItemInfo};\n\n";
    content_ += "#[derive(Debug)]\n";
    content_ += "struct RenameCallbacks;\n\n";
    content_ += "impl ParseCallbacks for RenameCallbacks {\n";
    content_ += "    fn item_name(&self, original_item_name: ItemInfo<'_>) -> Option<String> {\n";
    content_ += "        let mut renamed = String::from(original_item_name.name);\n";
    content_ += "        if original_item_name.name == \"DDS_CString\" {\n";
    content_ += "            renamed = \"DDSCString\".to_string();\n";
    content_ += "        }\n";
    content_ += "        renamed = renamed.replace(\"DDS_LongLong\", \"LLong\");\n";
    content_ += "        renamed = renamed.replace(\"DDS_LongDouble\", \"LDouble\");\n";
    content_ += "        renamed = renamed.replace(\"DDS_\", \"\");\n";
    content_ += "        renamed = renamed.replace(\"_iterator\", \"Iterator\");\n";
    content_ += "        Some(renamed)\n";
    content_ += "    }\n";
    content_ += "}\n\n";
    content_ += "fn main() {\n";
    content_ += "    let travodds_c_path = env::var(\"TRAVODDS_C_PATH\").unwrap_or_else(|_| {\n";
    content_ += "        println!(\"Please set the TRAVODDS_C_PATH environment variable to the path of the travodds_c library.\");\n";
    content_ += "        std::process::exit(1);\n";
    content_ += "    });\n";
    content_ += "    let travodds_path = env::var(\"TRAVODDS_PATH\").unwrap_or_else(|_| {\n";
    content_ += "        println!(\"Please set the TRAVODDS_PATH environment variable to the path of the travodds_c library.\");\n";
    content_ += "        std::process::exit(1);\n";
    content_ += "    });\n";
    content_ += "    println!(\"cargo:rustc-link-search=native={}/lib\", travodds_c_path);\n";
    content_ += "    println!(\"cargo:rustc-link-search=native={}/lib\", travodds_path);\n";
    content_ += "    println!(\"cargo:rustc-link-lib=static=travoddscz\");\n";
    content_ += "    println!(\"cargo:rustc-link-lib=static=travoddsstatic\");\n\n";
    content_ += "    cc::Build::new()\n";
    content_ += "        .file(\"" + packageName + ".cpp\")\n";
    content_ += "        .file(\"" + packageName + "TypeSupport.cpp\")\n";
    content_ += "        .include(format!(\"{}/include\", travodds_c_path))\n";
    content_ += "        .include(format!(\"{}/include\", travodds_path))\n";
    content_ += "        .compile(\"" + packageName + "\");\n\n";
    content_ += "    let bindings = bindgen::Builder::default()\n";
    content_ += "        .clang_arg(format!(\"-I{}/include\", travodds_c_path))\n";
    content_ += "        .header(\"" + packageName + ".h\")\n";
    content_ += "        .header(\"" + packageName + "TypeSupport.h\")\n";
    content_ += "        .allowlist_file(\".*" + packageName + ".h\")\n";
    content_ += "        .allowlist_file(\".*" + packageName + "TypeSupport.h\")\n";
    content_ += "        .allowlist_recursively(false)\n";
    content_ += "        .parse_callbacks(Box::new(RenameCallbacks))\n";
    content_ += "        .generate()\n";
    content_ += "        .expect(\"Unable to generate bindings\");\n";
    content_ += "    let out_path = PathBuf::from(env::current_dir().unwrap());\n";
    content_ += "    bindings\n";
    content_ += "        .write_to_file(out_path.join(\"" + packageName + ".rs\"))\n";
    content_ += "        .expect(\"Couldn't write " + packageName + " bindings!\");\n";
    content_ += "    println!(\"cargo:rustc-link-lib=static=" + packageName + "\");\n";
    content_ += "}\n";
}
